

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=&#34;auto&#34;>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" type="image/png" href="/img/favicon.png">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="CodeHope">
  <meta name="author" content="CodeHope">
  <meta name="keywords" content="希望">
  <title>Spring中AOP编程(上)代理模式 - CodeHope</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      
        
          
          
          
        
        <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.22.0/themes/prism-tomorrow.min.css" />
      
      
        <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.22.0/plugins/line-numbers/prism-line-numbers.min.css" />
      
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" />
  



<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"quancundexiwang.wang","root":"/","version":"1.8.7","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":true,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"onlypost":true},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":"Mi65hxq7VAFUDwOLeIGAOgiV-gzGzoHsz","app_key":"hMuhiD4FRqhns4giqLiEH9HG","server_url":null}}};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.3.0"></head>


<body>
  <header style="height: 80vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/">&nbsp;<strong>CodeHope</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                村头
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                我
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;</a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" href="javascript:">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('http://qiniuyun.quancundexiwang.wang/20210310182526.png') repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="Spring中AOP编程(上)代理模式">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2021-03-20 16:14" pubdate>
        2021年3月20日 下午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      6k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      74
       分钟
    </span>
  

  
  
</div>

            
          </div>

          
            <div class="scroll-down-bar">
              <i class="iconfont icon-arrowdown"></i>
            </div>
          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">Spring中AOP编程(上)代理模式</h1>
            
            <div class="markdown-body">
              <h1 id="AOP编程-上（静态代理和动态代理）"><a href="#AOP编程-上（静态代理和动态代理）" class="headerlink" title="AOP编程-上（静态代理和动态代理）"></a>AOP编程-上（静态代理和动态代理）</h1><p>(<code>Aspect Oriented Programming</code>)</p>
<h2 id="1-基本概念"><a href="#1-基本概念" class="headerlink" title="1.基本概念"></a>1.基本概念</h2><blockquote>
<p>随着软件世界不断复杂化，传统的OOP(面向对象)建模思路已经不足以很好的处理好开发时所面临的种种挑战.</p>
<p>AOP(Aspect Orient Programming)应运而生，它和OOP建模方式并不冲突，它是OOP编程的一种有效补充。</p>
<p>利用AOP可以对业务逻辑的各个部分进行隔离，从而使得业务逻辑各部分之间的耦合度降低，提高程序的可重用性，同时提高了开发的效率。</p>
<p>AOP是一种编程范式，目的是为了将跨领域的关注点分离出来以达到模块化。它可以向现存代码中增加行为逻辑而不用修改原有代码，它是通过指定切入点（pointcut）来实现的，例如向以set为开头的函数（function）中增加日志功能。它可以实现将一些不是核心的业务逻辑（如日志等）添加到程序中，而不会使核心代码混乱。AOP为面向方面的软件开发奠定了基础.</p>
</blockquote>
<p>从定义中，我们提取几个关键字：</p>
<ul>
<li>编程范式，和面向对象编程类似，AOP也是一种编程范式，它是面向切面编程</li>
<li>模块化，将程序模块化是AOP的追求目标</li>
<li>非核心业务逻辑，AOP应用于日志、监控等这种非核心业务中 </li>
</ul>
<p><img src="http://qiniuyun.quancundexiwang.wang/20210318175635" srcset="/img/loading.gif" alt="img"></p>
<p>从图中可以看出，业务A和业务B中都有log业务，面向切面的编程思想就将这些<code>log</code>业务从主业务中剥离出来，单独形成一个切面<code>（Aspect）</code>，然后在切面中进行处理<code>（Advice）</code>.</p>
 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>【生活案例】</p>

<p>比如我们需要去租房，那么房东就是需要为我们处理业务的人，关于租房的核心业务，对于房东来说，就是签订合同，以及收钱，</p>
<p>但是在通常情况下，需要广告，传单这些手段，来告诉我们去知道哪里有房子可以租，但是这些对于房东租房这个业务来说来说，不是业务的核心，因为他的目的只需要签合同，收房租，这才是他真正的业务。</p>
<p>那么一般打广告，看房子这些业务我们在日常生活中，基本都交给一些中介来做，就由中介帮助房东，通过广告的形式，找到需要租房的人，完成房东除业务之外需要做的事情。</p>
<p><img src="http://qiniuyun.quancundexiwang.wang/image-20200422105949613.png" srcset="/img/loading.gif" alt="image-20200422105949613"></p>
<h2 id="2-代理设计模式"><a href="#2-代理设计模式" class="headerlink" title="2.代理设计模式"></a>2.代理设计模式</h2><p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【问题1】什么是代理设计模式？</p>

<p>通过代理的类，为原始类、目标类（只负责核心业务功能的类），增加额外的功能（日志，性能监控….非核心业务功能）。</p>
<p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【问题2】这样做的好处是什么？</p>

<p>利于原始类的维护，降低业务的核心代码，和其他附加功能代码的耦合性，也增强了代码的复用性。</p>
<h2 id="3-名词解释"><a href="#3-名词解释" class="headerlink" title="3.名词解释"></a>3.名词解释</h2><p style='color:#035766;background:#feb856;padding:10px;font-weight:bolder;'>【目标类、原始类】：（实际案例中的房东）核心业务功能</p>

<p style='color:#035766;background:#feb856;padding:10px;font-weight:bolder;'>【目标方法、原始方法】：目标类、原始类中的方法，就是目标方法（原始方法）这些方法，也是完成具体核心功能的方法</p>

<p style='color:#035766;background:#feb856;padding:10px;font-weight:bolder;'>【额外功能，附加功能】：主要以性能，事务日志为代表的功能</p>

<h2 id="4-Sping中的静态代理"><a href="#4-Sping中的静态代理" class="headerlink" title="4.Sping中的静态代理"></a>4.Sping中的静态代理</h2><blockquote>
<p> 代理类=目标类(原始类)+额外功能 （房东收租+中介推广）</p>
</blockquote>
<p>那么我们一般的开发步骤是这样的，首先定义一个规范原始类业务方法的接口，然后原始类，实现接口并且实现其中的方法，然后开发一个专门用来做额外功能的类，也需要实现业务类实现的那个接口。</p>
 <img src="http://qiniuyun.quancundexiwang.wang/20210312153030.net&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?" srcset="/img/loading.gif"  />

<p>首先定义我们的核心接口,规定我们要完成业务代码</p>
<p><code>UserService.java</code> 规范</p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">aop</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">UserService</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">//注册</span>
    <span class="token keyword">void</span> <span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">,</span> <span class="token class-name">String</span> email<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//登录</span>
    <span class="token keyword">boolean</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>然后完成我们的原始类,继承接口，完成核心功能。</p>
<p><code>UserServiceImpl.java</code> 房东</p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">aop</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">UserService</span> <span class="token punctuation">&#123;</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">,</span> <span class="token class-name">String</span> email<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"专心实现我的注册业务功能---核心业务"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"专心实现我的登录业务功能---核心业务"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>下一步代理类（中介），代理帮我们应对调用，完成额外功能，以及调用我们的核心功能</p>
<p><code>UserServiceProxy.java</code></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">aop</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserServiceProxy</span> <span class="token keyword">implements</span> <span class="token class-name">UserService</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">private</span> <span class="token class-name">UserServiceImpl</span> userService <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UserServiceImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">,</span> <span class="token class-name">String</span> email<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"----额外功能-----日志-----"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
       	
        userService<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span>username<span class="token punctuation">,</span> password<span class="token punctuation">,</span> email<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//调用目标类的核心功能</span>
    <span class="token punctuation">&#125;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"----额外功能-----日志-----"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> userService<span class="token punctuation">.</span><span class="token function">login</span><span class="token punctuation">(</span>username<span class="token punctuation">,</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//调用目标类的核心功能</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>看一下使用感受！代理（中介）冲向市场业务的第一线，负责额外功能，(经过一系列推销，广告)随后触发核心的业务达到租房签合同的核心目的.</p>
<img src="http://qiniuyun.quancundexiwang.wang/0c8e100ba80f15ed321145a91d7afee8.gif" srcset="/img/loading.gif" style="zoom:30%;" />

<p><code>MainTest.java</code></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">aop<span class="token punctuation">.</span></span><span class="token class-name">UserServiceProxy</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MainTest</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">UserServiceProxy</span> userServiceProxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UserServiceProxy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        userServiceProxy<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">"codeHope"</span><span class="token punctuation">,</span> <span class="token string">"123456"</span><span class="token punctuation">,</span> <span class="token string">"codehope@gmail.com"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        userServiceProxy<span class="token punctuation">.</span><span class="token function">login</span><span class="token punctuation">(</span><span class="token string">"codeHope"</span><span class="token punctuation">,</span> <span class="token string">"123456"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>输出结果</p>
<div class="code-wrapper"><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">----额外功能-----日志-----
专心实现我的注册业务功能---核心业务
----额外功能-----日志-----
专心实现我的登录业务功能---核心业务<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div>
<p style='color:#035766;background:#feb856;padding:10px;font-weight:bolder;'>【简单总结】上面这种的代理类，我们一般称为静态代理类，就是一个业务原始类，对应着一个代理类，比如我们开发一个订单业务的类，可能还需要开发一个订单的业务代理类，这种都叫静态代理类</p>

 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>静态代理的存在的问题和缺点（每次租不同的房子，都要重新找一个中介，额外功能（广告，带你看房的功能）都差不多）</p>

<ul>
<li>静态代理文件数量过多，比如前面，每生产一个针对业务的原始类，都要我们自己去手动开发一个对应的代理类，有成千上百个原始类，那么就有成千上百个代理类，数量过多 ，实际上也不利于项目的管理</li>
<li>而且其实我们的额外功能在一个项目中，就那几种，你每个原始类的代理类都去写，其实代码结构是差不多，代码也会产生耦合。</li>
<li></li>
</ul>
<h2 id="5-Sping中的动态代理"><a href="#5-Sping中的动态代理" class="headerlink" title="5.Sping中的动态代理"></a>5.Sping中的动态代理</h2> <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>静态代理和动态代理在功能上，都是为我们的原始类，增加额外的功能，利于原始类和目标类的维护。

<p style='color:#035766;background:#feb856;padding:10px;font-weight:bolder;'>动态代理相对于静态代理的好处是什么？</p>

<ul>
<li><strong>静态代理</strong>，我们自己手动去写的代理类，存放在项目中，静态代理中代理类是在编译期生成的（当我们执行这个应用的时候，所有的都已经编译成class文件），静态代理相对动态代理来说效率会更高，但是会生成大量的代理类，不利于开发。</li>
<li><strong>动态代理</strong>，是在程序运行时，运用反射机制，在内存中临时为方法生成一个AOP对象，这个AOP对象包含了目标对象的全部方法，并且在特定的切点做了增强额外功能的处理，并回调原始对象的方法。</li>
</ul>
<p><strong>了解了动态代理，我们也来看一下，动态代理在<code>Spring</code>中的开发步骤！</strong></p>
<p><span style='border-radius:50%;width:30px;height:30px;background-color:#FF6C00;color:#2A3950;display:inline-block;text-align:center;font-weight:bolder;line-height:30px'>1</span> 第一步：创建原始对象（目标对象），完成核心业务功能，这里我们还是使用上面的<code>UserService.java</code></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">aop</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">UserService</span> <span class="token punctuation">&#123;</span>
    
    <span class="token keyword">void</span> <span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">,</span> <span class="token class-name">String</span> email<span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token keyword">boolean</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>然后核心实现类<code>UserServiceImpl</code>，实现接口,完成业务的具体实现</p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">aop</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">UserService</span> <span class="token punctuation">&#123;</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">,</span> <span class="token class-name">String</span> email<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"专心实现我的注册业务功能---核心业务"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"专心实现我的登录业务功能---核心业务"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>然后交给<code>Spring</code>配置管理对象</p>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>aop.UserServiceImpl<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>userServiceImpl<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>bean</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div>
<p><span style='border-radius:50%;width:30px;height:30px;background-color:#C30F2A;color:#F7FBF8;display:inline-block;text-align:center;font-weight:bolder;line-height:30px'>2</span>  第二步：引入动态代理的依赖到我们的spring项目（动态代理是spring帮我们完成）</p>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token comment">&lt;!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">></span></span>org.springframework<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">></span></span>spring-aop<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">></span></span>5.3.4<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">></span></span>

<span class="token comment">&lt;!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">></span></span>org.aspectj<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">></span></span>aspectjweaver<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">></span></span>1.9.6<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">></span></span>

<span class="token comment">&lt;!-- https://mvnrepository.com/artifact/aspectj/aspectjrt --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">></span></span>aspectj<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">></span></span>aspectjrt<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">></span></span>1.5.3<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">></span></span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>


<p><span style='border-radius:50%;width:30px;height:30px;background-color:#E1D20F;color:#0867EF;display:inline-block;text-align:center;font-weight:bolder;line-height:30px'>3</span> 第三步，使用<code>MethodBeforeAdvice</code>接口，开发额外的功能代理类，额外的功能写在接口的实现类<code>before</code>方法中！</p>
<p>这个额外功能，运行在原始核心业务方法执行之前！</p>
<p><code>Before.java</code></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">dynamic</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>aop<span class="token punctuation">.</span></span><span class="token class-name">MethodBeforeAdvice</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span><span class="token class-name">Method</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> before <span class="token keyword">implements</span> <span class="token class-name">MethodBeforeAdvice</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/*作用：在运行核心业务的原始方法之前，所执行的额外功能*/</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">before</span><span class="token punctuation">(</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> objects<span class="token punctuation">,</span> <span class="token class-name">Object</span> o<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"===before实现类的额外功能====运行在核心业务之前======"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>Spring<code>xml</code>配置文件配置这个类，交给<code>Spring</code>管理</p>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dynamic.before<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>before<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>bean</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div>
<p><span style='border-radius:50%;width:30px;height:30px;background-color:#65E8BE;color:#E67881;display:inline-block;text-align:center;font-weight:bolder;line-height:30px'>4</span> 第四步，定义切入点（定义额外功能加入的位置），由程序员根据需要来决定额外功能加入给哪一个原始方法！</p>
<p>比如查询，不需要加入事务，注册需要加入事务。当然我们也可以选择，给原始类中的所有方法，都切入额外的功能。</p>
<p><code>application.xml</code></p>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>config</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!--execution(* *(..))这里使用的这个表达式表示，所有的原始方法，都被额外功能切入--></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>pointcut</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>execution(* *(..))<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">aop:</span>config</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div>
<p><span style='border-radius:50%;width:30px;height:30px;background-color:#C30F2A;color:#F7FBF8;display:inline-block;text-align:center;font-weight:bolder;line-height:30px'>5</span> 第五步：组装，将额外功能，和切入点进行整合。</p>
<p>大佬就是大佬学的东西都和我们不一样<code>application.xml</code></p>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>config</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>pointcut</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>execution(* *(..))<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
    <span class="token comment">&lt;!-- 将额外功能和切点整合！指定切点是要切入那些额外功能 --></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>advisor</span> <span class="token attr-name">advice-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>before<span class="token punctuation">"</span></span> <span class="token attr-name">pointcut-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">aop:</span>advisor</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">aop:</span>config</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>


<p>完成上面开发步骤：我们需要注意的几个东西</p>
<p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【注意1】我们完成上面所有的步骤，好像并没有让我们的原始类与额外功能类，在配置上有什么关联，我们只是定义了切入点和额外功能类的关联，那么Spring如何知道，哪些类是需要额外功能切入，切入到那些方法中的呢？</p>

<p>其实一切的答案还是在定义切入点的那个表达式中！ <code>expression=&quot;execution(* *(..))&quot;</code>,不同表达式，代表了不同的范围。</p>
<p>我们使用的这个表达式，代表所有的类，类中的任何方法，都会被我们配置的切入点切入，而且切入的还是我们定义的那个额外功能。所以我们不需要手动的让切入点与我们的原始类进行关联配置，只需要对切入点指定一个范围，他会自动去帮我们决定是否要对这个原始方法，进行切入。</p>
<p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【注意2】我们定义了切入点后，如果我们通过Spring去实例化一个类的实例对象，如果这个类是在切入点规定的范围内，那么我们拿到的是已经帮我们处理好的代理对象</p>

<p><code>MainTest.java</code></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">aop<span class="token punctuation">.</span></span><span class="token class-name">UserService</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">aop<span class="token punctuation">.</span></span><span class="token class-name">UserServiceImpl</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ApplicationContext</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span><span class="token class-name">ClassPathXmlApplicationContext</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MainTest</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">ApplicationContext</span> applicationContext <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassPathXmlApplicationContext</span><span class="token punctuation">(</span><span class="token string">"./application.xml"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">UserService</span> userService <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">UserService</span><span class="token punctuation">)</span> applicationContext<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">"userServiceImpl"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        userService<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">"codeHope"</span><span class="token punctuation">,</span><span class="token string">"123"</span><span class="token punctuation">,</span><span class="token string">"123@gmail.com"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>运行结果,运行的是<code>Spring</code>帮我们实现的代理类</p>
<div class="code-wrapper"><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">&#x3D;&#x3D;&#x3D;before实现类的额外功能&#x3D;&#x3D;&#x3D;&#x3D;运行在核心业务之前&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;
专心实现我的注册业务功能---核心业务<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div>
<p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【注意3】存储代理对象实例的引用类型的问题</p>

<p><code>Spring</code>创建的代理对象默认是<strong>基于接口代理</strong>，也就是需要接口类的引用，来存储我们的代理对象。（和静态代理相似，代理类和原始类都是接口类的实现，那么按照正常设计思维，一般会选择接口类，作为实例对象储存的引用）</p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">UserService</span> userService <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">UserService</span><span class="token punctuation">)</span> applicationContext<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">"userServiceImpl"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div>
<p>那么如果，我们想使用原始类来作为代理类的存储引用的话，需要给aop:config配置<code>proxy-target-class=true</code>，代表基于原始类去代理</p>
<p>否则就会报错</p>
<div class="code-wrapper"><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">Exception in thread &quot;main&quot; java.lang.ClassCastException: class com.sun.proxy.$Proxy5 cannot be cast to class aop.UserServiceImpl (com.sun.proxy.$Proxy5 and aop.UserServiceImpl are in unnamed module of loader &#39;app&#39;) at MainTest.main(MainTest.java:9)<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div>
<p>配置完了就可以了</p>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>config</span> <span class="token attr-name">proxy-target-class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>pointcut</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>execution(* *(..))<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>advisor</span> <span class="token attr-name">advice-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>before<span class="token punctuation">"</span></span> <span class="token attr-name">pointcut-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">aop:</span>advisor</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">aop:</span>config</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div>
<div class="code-wrapper"><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">&#x3D;&#x3D;&#x3D;before实现类的额外功能&#x3D;&#x3D;&#x3D;&#x3D;运行在核心业务之前&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;
专心实现我的注册业务功能---核心业务<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div>
 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>【细节分析1】Spring创建的动态代理类是在哪里？？？？</p>

<p>作为<code>Spring</code>动态代理类，是在运行时，通过<strong>动态字节码</strong>在JVM创建的，等程序运行结束后，那么这个创建的动态代理类会和虚拟机一起销毁。</p>
<p>什么是动态字节码？通过第三方动态字节码的框架，在JVM中创建对应类的字节码，进而创建对象，虚拟机结束时，动态字节码跟着消失</p>
<p><img src="http://qiniuyun.quancundexiwang.wang/image-20210319123557414.png" srcset="/img/loading.gif" alt="image-20210319123557414"></p>
<p style='color:#035766;background:#feb856;padding:10px;font-weight:bolder;'>【简单总结】动态代理，不需要我们定义类文件，都是通过动态字节码技术在JVM中动态创建代理类，解决了静态代理，每个原始类，都要去创建一个代理类的冗余问题</p>

 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>【细节分析2】Spring动态代理编程会简化代理的开发？</p>

<p>当我们的项目中的业务变得更大，原始类更多了，我们只需要根据一定规则的范围来指定哪些类需要创建代理对象，就可以，不需要一个一个去编写对应的代理对象文件。</p>
 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>【细节分析2】Spring动态代理额外功能维护性大大增强了</p>

<p>比如静态代理中我们一个个的去实现不同原始类功能相似的代理类，然后辛辛苦苦写完了，发现需要改一些额外功能的地方，然后你那么多针对不同原始类的代理类的额外功能，都要修改，想想就刺激。</p>
<h2 id="6-Spring动态代理详解"><a href="#6-Spring动态代理详解" class="headerlink" title="6.Spring动态代理详解"></a>6.Spring动态代理详解</h2><h3 id="6-1-额外功能的详解"><a href="#6-1-额外功能的详解" class="headerlink" title="6.1 额外功能的详解"></a>6.1 额外功能的详解</h3><h4 id="a-MethodBeforeAdvice详解"><a href="#a-MethodBeforeAdvice详解" class="headerlink" title="a) MethodBeforeAdvice详解"></a>a) <code>MethodBeforeAdvice</code>详解</h4><p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【额外功能，运行在核心功能之前】</p>

<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java">`<span class="token function">before</span><span class="token punctuation">(</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">Object</span> target<span class="token punctuation">)</span>`方法参数的含义<span class="token keyword">package</span> <span class="token namespace">dynamic</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>aop<span class="token punctuation">.</span></span><span class="token class-name">MethodBeforeAdvice</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span><span class="token class-name">Method</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyLog</span> <span class="token keyword">implements</span> <span class="token class-name">MethodBeforeAdvice</span> <span class="token punctuation">&#123;</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">before</span><span class="token punctuation">(</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">Object</span> target<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"=====额外的功能====日志功能==login=="</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>`before(Method method, Object[] args, Object target)`方法参数的含义</p>

<p><img src="http://qiniuyun.quancundexiwang.wang/20210319174524.png" srcset="/img/loading.gif" alt="image-20210319174517539"></p>
<p>通过debug可以看到</p>
<p>第一个参数 <code>Method method</code>表示的被调用的核心业务的那个方法！</p>
<p>第二个参数 <code>Object[] args</code>表示被调用的核心业务的方法，需要的参数！</p>
<p>第三个参数 <code>Object target</code>表示原始处理核心业务的那个对象！</p>
 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>上面的三个参数在实战中，根据需要去使用啦！</p>

<h4 id="b-MethodInterceptor方法拦截器"><a href="#b-MethodInterceptor方法拦截器" class="headerlink" title="b)MethodInterceptor方法拦截器"></a>b)<code>MethodInterceptor</code>方法拦截器</h4><p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【额外功能，可以运行在执行前，后或者前后同时执行额外功能,或者在原始功能抛出异常时执行(TryCatch捕获原始功能的异常)】可以根据需要自己proceed()执行啦</p>

<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">dynamic</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>aopalliance<span class="token punctuation">.</span>intercept<span class="token punctuation">.</span></span><span class="token class-name">MethodInterceptor</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>aopalliance<span class="token punctuation">.</span>intercept<span class="token punctuation">.</span></span><span class="token class-name">MethodInvocation</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Interceptor</span> <span class="token keyword">implements</span> <span class="token class-name">MethodInterceptor</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/** 
     * methodInvocation 代表额外功能增加的那个原始方法（Method）！
     *
     * methodInvocation.proceed(); //执行原始方法
     *
     * 我们需要在invoke()中，自己去调用。所以我们能控制了原始功能的运行时机
     *
     * Object返回值：原始方法执行完成的返回值！
     * */</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">MethodInvocation</span> methodInvocation<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"=====额外功能==========Log====before===="</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Object</span> obj <span class="token operator">=</span> methodInvocation<span class="token punctuation">.</span><span class="token function">proceed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//执行原始方法</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"=====额外功能==========Log====after===="</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> obj<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>  public Object invoke(MethodInvocation methodInvocation)  方法，参数，返回值的含义</p>

<ul>
<li><p><code>methodInvocation</code> 代表额外功能增加的那个原始方法（Method）！</p>
</li>
<li><p><code>methodInvocation.proceed();</code> //执行原始方法</p>
</li>
<li><p>我们需要在<code>invoke()</code>中，自己去调用。所以我们能控制了原始功能的运行时机</p>
</li>
<li><p><code>Object</code>返回值：原始方法执行完成的返回值！</p>
<img src="http://qiniuyun.quancundexiwang.wang/20210312153030.net&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?" srcset="/img/loading.gif" style='zoom:60%' />

</li>
</ul>
<p>首先完成切面的配置</p>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>aop.UserServiceImpl<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>userServiceImpl<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>bean</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dynamic.Interceptor<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>interceptor<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>bean</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>config</span> <span class="token attr-name">proxy-target-class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>pointcut</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>execution(* *(..))<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>advisor</span> <span class="token attr-name">advice-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>interceptor<span class="token punctuation">"</span></span> <span class="token attr-name">pointcut-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">aop:</span>advisor</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">aop:</span>config</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p><code>MainTest.java</code></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">aop<span class="token punctuation">.</span></span><span class="token class-name">UserService</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">aop<span class="token punctuation">.</span></span><span class="token class-name">UserServiceImpl</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ApplicationContext</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span><span class="token class-name">ClassPathXmlApplicationContext</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MainTest</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">ApplicationContext</span> applicationContext <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassPathXmlApplicationContext</span><span class="token punctuation">(</span><span class="token string">"./application.xml"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">UserService</span> userService <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">UserService</span><span class="token punctuation">)</span> applicationContext<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">"userServiceImpl"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        userService<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">"codeHope"</span><span class="token punctuation">,</span><span class="token string">"123"</span><span class="token punctuation">,</span><span class="token string">"123@gmail.com"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>执行结果</p>
<div class="code-wrapper"><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;额外功能&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;Log&#x3D;&#x3D;&#x3D;&#x3D;before&#x3D;&#x3D;&#x3D;&#x3D;
专心实现我的注册业务功能---核心业务
&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;额外功能&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;Log&#x3D;&#x3D;&#x3D;&#x3D;after&#x3D;&#x3D;&#x3D;&#x3D;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></div>
 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'> MethodInterceptor 可以影响原始方法的返回值 </p>

<p><code>UserServiceImpl.java</code>中可以看到<code>login</code>的返回值为<code>true</code></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">aop</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">UserService</span> <span class="token punctuation">&#123;</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">,</span> <span class="token class-name">String</span> email<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"专心实现我的注册业务功能---核心业务"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"专心实现我的登录业务功能---核心业务"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>然后我们将<code>invoke</code>中的返回值，手动写为<code>false</code></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">dynamic</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>aopalliance<span class="token punctuation">.</span>intercept<span class="token punctuation">.</span></span><span class="token class-name">MethodInterceptor</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>aopalliance<span class="token punctuation">.</span>intercept<span class="token punctuation">.</span></span><span class="token class-name">MethodInvocation</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Interceptor</span> <span class="token keyword">implements</span> <span class="token class-name">MethodInterceptor</span> <span class="token punctuation">&#123;</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">MethodInvocation</span> methodInvocation<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"=====额外功能==========Log====before===="</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Object</span> obj <span class="token operator">=</span> methodInvocation<span class="token punctuation">.</span><span class="token function">proceed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//执行原始方法</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"=====额外功能==========Log====after===="</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//return obj;</span>
        <span class="token keyword">return</span> <span class="token boolean">false</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>执行<code>MainTest.java</code></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">aop<span class="token punctuation">.</span></span><span class="token class-name">UserService</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ApplicationContext</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span><span class="token class-name">ClassPathXmlApplicationContext</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MainTest</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">ApplicationContext</span> applicationContext <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassPathXmlApplicationContext</span><span class="token punctuation">(</span><span class="token string">"./application.xml"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">UserService</span> userService <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">UserService</span><span class="token punctuation">)</span> applicationContext<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">"userServiceImpl"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>userService<span class="token punctuation">.</span><span class="token function">login</span><span class="token punctuation">(</span><span class="token string">"codeHope"</span><span class="token punctuation">,</span> <span class="token string">"123"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<div class="code-wrapper"><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;额外功能&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;Log&#x3D;&#x3D;&#x3D;&#x3D;before&#x3D;&#x3D;&#x3D;&#x3D;
专心实现我的登录业务功能---核心业务
&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;额外功能&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;Log&#x3D;&#x3D;&#x3D;&#x3D;after&#x3D;&#x3D;&#x3D;&#x3D;
false<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div>
<h3 id="6-2-切入点的详解"><a href="#6-2-切入点的详解" class="headerlink" title="6.2 切入点的详解"></a>6.2 切入点的详解</h3><div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>pointcut</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>execution(* *(..))<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div>
<ul>
<li><p>切入点:id 表示这个<strong>切入点的名称，随便起</strong></p>
</li>
<li><p>expression 这个用来指定，那些类，那些方法可以被这个切入点切入</p>
</li>
<li><p><code>execution</code>是<strong>切入点函数</strong>，</p>
</li>
<li><p><code>* *(..)</code>是用来选择范围的<strong>切入点表达式</strong></p>
</li>
</ul>
<p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【切入点表达式】详解</p>

<p>我们定义一个函数 通常主要由<code>4</code>部分组成 <strong>修饰符 返回值 方法名 参数</strong></p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">Integer</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token class-name">Integer</span> num1<span class="token punctuation">,</span> <span class="token class-name">Integer</span> num2<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">return</span> num1 <span class="token operator">+</span> num2<span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></div>
<img src="http://qiniuyun.quancundexiwang.wang/image-20210319225312248.png?" srcset="/img/loading.gif" alt="image-20210319225312248" style="zoom:67%;" />

<p>当你想修饰符和返回值单独定义也是可以的,add*表示add开头的函数名</p>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>pointcut</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>execution(public void add*(*,String))<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div>
<p>以下是官方文档中提到的一些表达式：</p>
<div class="code-wrapper"><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token function">execution</span><span class="token punctuation">(</span><span class="token keyword">public</span> <span class="token operator">*</span> <span class="token operator">*</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">//匹配所有public方法</span>
    
<span class="token function">execution</span><span class="token punctuation">(</span><span class="token operator">*</span> set<span class="token operator">*</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">//匹配所有方法名开头为set的方法</span>
    
<span class="token function">execution</span><span class="token punctuation">(</span><span class="token operator">*</span> <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xyz<span class="token punctuation">.</span>service<span class="token punctuation">.</span></span>AccountService</span><span class="token punctuation">.</span>*<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">//匹配AccountService下的所有方法</span>
    
<span class="token function">execution</span><span class="token punctuation">(</span><span class="token operator">*</span> com<span class="token punctuation">.</span>xyz<span class="token punctuation">.</span>service<span class="token punctuation">.</span>*<span class="token punctuation">.</span>*<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">//匹配service包下的所有方法</span>
    
<span class="token function">execution</span><span class="token punctuation">(</span><span class="token operator">*</span> com<span class="token punctuation">.</span>xyz<span class="token punctuation">.</span>service<span class="token punctuation">.</span><span class="token punctuation">.</span>*<span class="token punctuation">.</span>*<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">//匹配service包或其子包下的所有方法</span>
    
<span class="token function">within</span><span class="token punctuation">(</span>com<span class="token punctuation">.</span>xyz<span class="token punctuation">.</span>service<span class="token punctuation">.</span>*<span class="token punctuation">)</span><span class="token comment">//匹配service包下的所有方法</span>
    
<span class="token function">within</span><span class="token punctuation">(</span>com<span class="token punctuation">.</span>xyz<span class="token punctuation">.</span>service<span class="token punctuation">.</span><span class="token punctuation">.</span>*<span class="token punctuation">)</span><span class="token comment">//匹配service包或其子包下的所有方法</span>
    
<span class="token keyword">this</span><span class="token punctuation">(</span><span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xyz<span class="token punctuation">.</span>service<span class="token punctuation">.</span></span>AccountService</span><span class="token punctuation">)</span><span class="token comment">//匹配所有实现了AccountService接口的类的代理类的方法（注意是代理类）</span>
    
<span class="token function">target</span><span class="token punctuation">(</span><span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xyz<span class="token punctuation">.</span>service<span class="token punctuation">.</span></span>AccountService</span><span class="token punctuation">)</span><span class="token comment">//匹配所有实现了AccountService接口的类的方法（注意是本类）</span>
    
<span class="token function">args</span><span class="token punctuation">(</span><span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span>Serializable</span><span class="token punctuation">)</span><span class="token comment">//匹配只有一个入参，且入参实现了Serializable接口的方法</span>
    
<span class="token annotation punctuation">@target</span><span class="token punctuation">(</span><span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>transaction<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span>Transactional</span><span class="token punctuation">)</span><span class="token comment">//匹配类上标注了@Transactional注解的类中方法</span>
    
<span class="token annotation punctuation">@within</span><span class="token punctuation">(</span><span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>transaction<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span>Transactional</span><span class="token punctuation">)</span><span class="token comment">//匹配运行时子类上标注了@Transactional注解的类中方法</span>
    
<span class="token annotation punctuation">@annotation</span><span class="token punctuation">(</span><span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>transaction<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span>Transactional</span><span class="token punctuation">)</span><span class="token comment">//匹配所有打了@Transactional注解的方法</span>
    
<span class="token annotation punctuation">@args</span><span class="token punctuation">(</span><span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xyz<span class="token punctuation">.</span>security<span class="token punctuation">.</span></span>Classified</span><span class="token punctuation">)</span><span class="token comment">//匹配只有一个入参，且运行时入参有@Classified注解的方法</span>
    
<span class="token function">bean</span><span class="token punctuation">(</span>tradeService<span class="token punctuation">)</span><span class="token comment">//匹配命名为tradeService的类的方法</span>
    
<span class="token function">bean</span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token class-name">Service</span><span class="token punctuation">)</span><span class="token comment">//匹配命名后缀为Service的类的方法</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>config</span> <span class="token attr-name">proxy-target-class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>pointcut</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>execution(public void add*(*,String))<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>advisor</span> <span class="token attr-name">advice-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>interceptor<span class="token punctuation">"</span></span> <span class="token attr-name">pointcut-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pc<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">aop:</span>advisor</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token namespace">aop:</span>config</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div>
<p>当我们设置这样的切入点，那么我们上面的测试都不会被切入，额外功能也不会再那些业务代码中执行</p>
<div class="code-wrapper"><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">专心实现我的登录业务功能---核心业务
true<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div>
 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>【注意】非Java.lang包中的类型，需要写类的全限定名称</p>

<h4 id="a-方法切入点"><a href="#a-方法切入点" class="headerlink" title="a) 方法切入点"></a>a) 方法切入点</h4><p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【指定特定方法，作为额外功能加入的切入点】</p>

<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown"><span class="token list punctuation">*</span>  <span class="token italic"><span class="token punctuation">*</span><span class="token content">(..)  --> 所有方法
</span><span class="token punctuation">*</span></span> ---> 修饰符 返回值
<span class="token list punctuation">*</span> ---> 方法名
()---> 参数表
..---> 对于参数没有要求 (参数有没有，参数有几个都行，参数是什么类型的都行)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<ul>
<li><p>定义login方法作为切入点</p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown"><span class="token list punctuation">*</span> login(..)

<span class="token title important"><span class="token punctuation">#</span> 定义register作为切入点</span>
<span class="token list punctuation">*</span> register(..)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div></li>
<li><p>定义login方法且login方法有两个字符串类型的参数 作为切入点</p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown"><span class="token list punctuation">*</span> login(String,String)

<span class="token title important"><span class="token punctuation">#</span>注意：非java.lang包中的类型，必须要写全限定名</span>
<span class="token list punctuation">*</span> register(com.baizhiedu.proxy.User)

<span class="token title important"><span class="token punctuation">#</span> ..可以和具体的参数类型连用</span>
<span class="token list punctuation">*</span> login(String,..)  --> login(String),login(String,String),login(String,com.baizhiedu.proxy.User)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></li>
<li><p>精准方法切入点限定</p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown">修饰符 返回值         包.类.方法(参数)

<span class="token code keyword">    *               com.baizhiedu.proxy.UserServiceImpl.login(..)
    *               com.baizhiedu.proxy.UserServiceImpl.login(String,String)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></div>
<h4 id="b-类的切入点"><a href="#b-类的切入点" class="headerlink" title="b) 类的切入点"></a>b) 类的切入点</h4></li>
</ul>
<p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【指定特定类，作为额外功能加入的切入点，自然这个类的所有方法，都会加上额外的功能】</p>

<ul>
<li><p>语法1</p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span>类中的所有方法加入了额外功能 </span>
<span class="token list punctuation">*</span> com.baizhiedu.proxy.UserServiceImpl.*(..)  <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div></li>
<li><p>语法2 </p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span>忽略包</span>
<span class="token list punctuation">1.</span> 类只存在一级包  com.UserServiceImpl
<span class="token list punctuation">*</span> <span class="token italic"><span class="token punctuation">*</span><span class="token content">.UserServiceImpl.</span><span class="token punctuation">*</span></span>(..)

<span class="token list punctuation">2.</span> 类存在多级包    com.baizhiedu.proxy.UserServiceImpl
<span class="token list punctuation">*</span> <span class="token italic"><span class="token punctuation">*</span><span class="token content">..UserServiceImpl.</span><span class="token punctuation">*</span></span>(..)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
<h4 id="c-包切入点"><a href="#c-包切入点" class="headerlink" title="c) 包切入点"></a>c) 包切入点</h4></li>
</ul>
<p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【指定包作为额外功能加入的位置，自然包中的所有类及其方法都会加入额外的功能】</p>

<ul>
<li><p>语法1</p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span>切入点包中的所有类，必须在proxy中，不能在proxy包的子包中</span>
<span class="token list punctuation">*</span> com.baizhiedu.proxy.<span class="token italic"><span class="token punctuation">*</span><span class="token content">.</span><span class="token punctuation">*</span></span>(..)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div></li>
<li><p>语法2</p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span>切入点当前包及其子包都生效 </span>
<span class="token list punctuation">*</span> com.baizhiedu.proxy..<span class="token italic"><span class="token punctuation">*</span><span class="token content">.</span><span class="token punctuation">*</span></span>(..) <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></div>
<h4 id="d-切入点函数"><a href="#d-切入点函数" class="headerlink" title="d) 切入点函数"></a>d) 切入点函数</h4></li>
</ul>
<p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【切入点函数：用于执行切入点表达式】</p>

<ol>
<li><p><code>execution</code></p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown">最为重要的切入点函数，功能最全。
执行 方法切入点表达式 类切入点表达式 包切入点表达式 

弊端：execution执行切入点表达式 ，书写麻烦
     execution(<span class="token italic"><span class="token punctuation">*</span><span class="token content"> com.codehope.proxy..</span><span class="token punctuation">*</span></span>.*(..))
     
注意：其他的切入点函数 简化是execution书写复杂度，功能上完全一致<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></li>
<li><p><code>args</code>（专注于匹配方法的参数）</p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown">作用：主要用于函数(方法) 参数的匹配

切入点：方法参数必须得是2个字符串类型的参数

execution(<span class="token italic"><span class="token punctuation">*</span><span class="token content"> </span><span class="token punctuation">*</span></span>(String,String))

args(String,String)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></li>
<li><p><code>within</code></p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown">作用：主要用于进行类、包切入点表达式的匹配

切入点：UserServiceImpl这个类

execution(<span class="token italic"><span class="token punctuation">*</span><span class="token content"> </span><span class="token punctuation">*</span></span>..UserServiceImpl.*(..))

within(*..UserServiceImpl)

execution(<span class="token italic"><span class="token punctuation">*</span><span class="token content"> com.baizhiedu.proxy..</span><span class="token punctuation">*</span></span>.*(..))

within(com.baizhiedu.proxy..*)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div></li>
<li><p>@annotation</p>
</li>
</ol>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml">作用：为具有特殊注解的方法加入额外功能

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">aop:</span>pointcut</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@annotation(com.codehope.Log)<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></div>
<h4 id="e-切入点逻辑运算"><a href="#e-切入点逻辑运算" class="headerlink" title="e)  切入点逻辑运算"></a>e)  切入点逻辑运算</h4><p style='color:#815abd;background:#fcdc01;padding:10px;font-weight:bolder;'>【   指的是 整合多个切入点函数一起配合工作，进而完成更为复杂的需求】</p>

<ul>
<li><p>and与操作</p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown">案例：login 同时 参数 2个字符串 

<span class="token list punctuation">1.</span> execution(* login(String,String))

<span class="token list punctuation">2.</span> execution(* login(..)) and args(String,String)
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre></div>
 <p style='color:#eaf1f8;background:#443da6;padding:10px;font-weight:bolder;'>【注意】与操作不同用于同种类型的切入点函数</p>

<p>案例：register方法 和 login方法作为切入点 ,不可能有一个方法既叫<code>Login</code>又<code>Register</code>啦</p>
<div class="code-wrapper"><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml">execution(* login(..)) or  execution(* register(..))<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></div></li>
<li><p>or或操作</p>
<div class="code-wrapper"><pre class="line-numbers language-markdown" data-language="markdown"><code class="language-markdown">案例：register方法 和 login方法作为切入点 

execution(<span class="token italic"><span class="token punctuation">*</span><span class="token content"> login(..)) or  execution(</span><span class="token punctuation">*</span></span> register(..))<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></div>
<img src="http://qiniuyun.quancundexiwang.wang/269969f172ab62a39d9a84891c333d29.jpeg?" srcset="/img/loading.gif" alt="269969f172ab62a39d9a84891c333d29" style="zoom:33%;" /></li>
</ul>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/Java/">Java</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/Spring%E5%9F%BA%E7%A1%80/">Spring基础</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！</p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/posts/53448/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">Spring框架AOP编程下（重要AOP概念解析）</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/posts/48793/">
                        <span class="hidden-mobile">Spring中BeanPostProcesser接口</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
              <!-- Comments -->
              <article class="comments" id="comments">
                
                
  <div id="vcomments"></div>
  <script type="text/javascript">
    Fluid.utils.waitElementVisible('vcomments', function() {
      Fluid.utils.createScript('https://cdn.jsdelivr.net/npm/valine@1.4.14/dist/Valine.min.js', function () {
        new Valine({
          el: "#vcomments",
          app_id: "Mi65hxq7VAFUDwOLeIGAOgiV-gzGzoHsz",
          app_key: "hMuhiD4FRqhns4giqLiEH9HG",
          placeholder: "说点什么",
          path: window.location.pathname,
          avatar: "retro",
          meta: ["nick","mail","link"],
          pageSize: "10",
          lang: "zh-CN",
          highlight: false,
          recordIP: false,
          serverURLs: "",
        });
      });
    });
  </script>
  <noscript>Please enable JavaScript to view the
    <a target="_blank" href="https://valine.js.org" rel="nofollow noopener noopener">comments powered by Valine.</a>
  </noscript>


              </article>
            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
    

  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  
  <!-- 备案信息 -->
  <div class="beian">
    <span>
      <a href="http://beian.miit.gov.cn/" target="_blank" rel="nofollow noopener">
        豫ICP备20009912号-1
      </a>
    </span>
    
  </div>


  
</footer>

<!-- SCRIPTS -->

  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":true,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" ></script>
<script  src="/js/debouncer.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  
    
      <script  src="/js/lazyload.js" ></script>
    
  



  
    
  



  <script  src="https://cdn.jsdelivr.net/npm/tocbot@4.12.0/dist/tocbot.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js" ></script>



  <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4.3.0/anchor.min.js" ></script>



  <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js" ></script>



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2.0.11/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
      typing(title)
      
    })(window, document);
  </script>



  <script  src="/js/local-search.js" ></script>
  <script>
    (function () {
      var path = "http://qiniuyun.quancundexiwang.wang/xmlSearch.xml";
      var inputArea = document.querySelector("#local-search-input");
      inputArea.onclick = function () {
        searchFunc(path, 'local-search-input', 'local-search-result');
        this.onclick = null
      }
    })()
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>



</body>
</html>
